package com.xdxc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xdxc.response.Result;
import com.xdxc.vo.AnswerVo;
import com.xdxc.entity.CorrectAnswerVo;
import com.xdxc.mapper.QuestionMapper;
import com.xdxc.model.entity.Answer;
import com.xdxc.model.entity.CorrectAnswer;
import com.xdxc.model.entity.Question;
import com.xdxc.service.AnswerService;
import com.xdxc.service.CorrectAnswerService;
import com.xdxc.service.QuestionService;
import com.xdxc.utils.CompletableFutureUtil;
import com.xdxc.utils.ListConverter;
import com.xdxc.vo.QuestionWithOptionsVo;
import io.lettuce.core.RedisClient;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class QuestionServiceImpl  extends ServiceImpl<QuestionMapper, Question> implements QuestionService {


    @Autowired
    private AnswerService answerService;

    @Autowired
    private CorrectAnswerService correctAnswerService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;



    @Override
    public List<QuestionWithOptionsVo> getQuestionBatchByIdList(List<Long> idList, Boolean haveAnalysis){
        Map<String, Object> relationData = CompletableFutureUtil.allOf(
                () -> this.list(new LambdaQueryWrapper<Question>().in(Question::getId,idList)),
                () -> answerService.list(new LambdaQueryWrapper<Answer>().in(Answer::getQuId,idList))
                        .stream().map(answer->{
                            AnswerVo answerVo = new AnswerVo();
                            BeanUtils.copyProperties(answer,answerVo);
                            return answerVo;
                        }).sorted(Comparator.comparing(
                                AnswerVo::getSort,
                                Comparator.nullsLast(Comparator.naturalOrder())
                        )).collect(Collectors.groupingBy(AnswerVo::getQuId))
        ).join();
        List<Question> questionList =(List<Question>) relationData.get("data0");
        Map<Long, List<AnswerVo>>  answerListMap =(Map<Long, List<AnswerVo >>) relationData.get("data1");

        List<QuestionWithOptionsVo>   questionWithOptionsVoList= questionList.parallelStream().map(question -> {
            QuestionWithOptionsVo questionWithOptionsVo = new QuestionWithOptionsVo();
            BeanUtils.copyProperties(question,questionWithOptionsVo);
            questionWithOptionsVo.setAnswerVoList(answerListMap.get(question.getId()));
            if (!haveAnalysis){
                questionWithOptionsVo.setAnalysis(null);
            }
            return questionWithOptionsVo;
        }).collect(Collectors.toList());
        return questionWithOptionsVoList;
    };
    @Override
    public List<QuestionWithOptionsVo> getQuestionBatchByIdListWithCorrectAnswer(List<Long> idList){

        if (idList.size()==0){
          return   null;
        }
        Map<String, Object> relationData = CompletableFutureUtil.allOf(
                () -> this.getQuestionBatchByIdList(idList,true)
        ).join();
        List<QuestionWithOptionsVo>  questionWithOptionsVoList =( List<QuestionWithOptionsVo> ) relationData.get("data0");
        CompletableFuture<List<CorrectAnswerVo>> correctAnswerFuture = CompletableFuture.supplyAsync(() ->
                correctAnswerService.list(new LambdaQueryWrapper<CorrectAnswer>().in(CorrectAnswer::getQuestionId, idList)).stream()
                        .map(answer->{
                            CorrectAnswerVo correctAnswerVo = new CorrectAnswerVo();
                            BeanUtils.copyProperties(answer,correctAnswerVo);
                            correctAnswerVo.setOptionIds(ListConverter.convertLongToStringList(answer.getOptionIds()));
                            return correctAnswerVo;
                        })
                        .collect(Collectors.toList()));
        Map<Long,  CorrectAnswerVo> correctAnswerVoMap=correctAnswerFuture.join().stream()
                .collect(Collectors.toMap(CorrectAnswerVo::getQuestionId,correctAnswerVo -> correctAnswerVo));

        List<QuestionWithOptionsVo> question=questionWithOptionsVoList.stream().peek(questionWithOptionsVo -> {
            questionWithOptionsVo.setCorrectAnswerVo(correctAnswerVoMap.get(questionWithOptionsVo.getId()));
        }).collect(Collectors.toList());
        return question;
    };

    @Override
    public Result<List<QuestionWithOptionsVo>> questionPage(Integer page, Integer size){

        // 创建分页对象
        Page<Question> questionPage = new Page<>(page, size);

        // 使用带有查询条件的分页查询（如果没有条件可以使用 queryWrapper）
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        // 可以添加排序等条件
        // queryWrapper.orderByDesc(Question::getCreateTime);

        Page<Question> pagedQuestions = this.page(questionPage, queryWrapper);

        List<Question> questionList = pagedQuestions.getRecords();
        List<Long> idList =  questionList.stream()
                .map(Question::getId)
                .collect(Collectors.toList());
        List<QuestionWithOptionsVo> questionWithOptionsVoList=  this.getQuestionWithCorrectAnswerPage(questionList,idList);
        Result  result= Result.success(questionWithOptionsVoList);
        result.setMsg("题目获取成功");
        result.add("totalPage",pagedQuestions.getTotal());
        result.add("currentPage",pagedQuestions.getCurrent());
        result.add("pageSize",pagedQuestions.getSize());
        return result;

    };

    @Override
    public QuestionWithOptionsVo getQuestionWithOptionById(Long quId, Boolean haveAnalysis){
        Map<String, Object> relationData = CompletableFutureUtil.allOf(
                () -> this.getOne(new LambdaQueryWrapper<Question>().eq(Question::getId,quId)),
                () -> answerService.list(new LambdaQueryWrapper<Answer>().eq(Answer::getQuId,quId))
                        .stream().map(answer -> {
                            AnswerVo answerVo = new AnswerVo();
                            BeanUtils.copyProperties(answer,answerVo);
                            return answerVo;
                        }).collect(Collectors.toList())
        ).join();
        Question  question =(Question) relationData.get("data0");
        QuestionWithOptionsVo questionWithOptionsVo=new QuestionWithOptionsVo();
        BeanUtils.copyProperties(question,questionWithOptionsVo);
        List<AnswerVo>  answerList =( List<AnswerVo> ) relationData.get("data1");
        questionWithOptionsVo.setAnswerVoList(answerList);
        if (!haveAnalysis){
            questionWithOptionsVo.setAnalysis(null);
        }
        return questionWithOptionsVo;
    };





    @Override
    public QuestionWithOptionsVo getQuestionByIdWithCorrectAnswer(Long quId){
        Map<String, Object> relationData = CompletableFutureUtil.allOf(
                () -> this.getQuestionWithOptionById(quId,true),
                () -> correctAnswerService.getOne(new LambdaQueryWrapper<CorrectAnswer>().eq(CorrectAnswer::getQuestionId,quId))
        ).join();

        // 现在可以安全地使用，relationData.get("data1") 会在出错时返回 null
        QuestionWithOptionsVo questionWithOptionsVo = (QuestionWithOptionsVo) relationData.get("data0");
        CorrectAnswerVo correctAnswerVo = new CorrectAnswerVo();
        if (relationData.get("data1") != null) {
            BeanUtils.copyProperties(relationData.get("data1"), correctAnswerVo);
        }

        questionWithOptionsVo.setCorrectAnswerVo(correctAnswerVo);
        return questionWithOptionsVo;
    };
    @Override
    public List<QuestionWithOptionsVo> getQuestionWithCorrectAnswerPage(List<Question> questionList,  List<Long> idList){

        if (idList.isEmpty()) {
            return null;
        }
        CompletableFuture<Map<Long, List<AnswerVo>>> answerFuture = CompletableFuture.supplyAsync(() ->
                answerService.list(new LambdaQueryWrapper<Answer>().in(Answer::getQuId, idList)).stream()
                        .map(answer->{
                            AnswerVo answerVo = new AnswerVo();
                            BeanUtils.copyProperties(answer, answerVo); // 源对象在前
                            return answerVo;
                        })
                        .collect(Collectors.groupingBy(AnswerVo::getQuId)));
        CompletableFuture<List<CorrectAnswerVo>> correctAnswerFuture = CompletableFuture.supplyAsync(() ->
                correctAnswerService.list(new LambdaQueryWrapper<CorrectAnswer>().in(CorrectAnswer::getQuestionId, idList)).stream()
                        .map(answer->{
                            CorrectAnswerVo correctAnswerVo = new CorrectAnswerVo();
                            BeanUtils.copyProperties(answer,correctAnswerVo);
                            correctAnswerVo.setOptionIds(ListConverter.convertLongToStringList(answer.getOptionIds()));
                            return correctAnswerVo;
                        })
                        .collect(Collectors.toList()));

        Map<Long, List<AnswerVo>> userAnswersMap=answerFuture.join();
        Map<Long,  CorrectAnswerVo> correctAnswerVoMap=correctAnswerFuture.join().stream()
                .collect(Collectors.toMap(CorrectAnswerVo::getQuestionId,correctAnswerVo -> correctAnswerVo));

        List<QuestionWithOptionsVo> questionWithOptionsVoList=questionList.stream().map(question->{
            QuestionWithOptionsVo questionWithOptionsVo=new QuestionWithOptionsVo();
            BeanUtils.copyProperties(question,questionWithOptionsVo);
            questionWithOptionsVo.setAnswerVoList(userAnswersMap.get(question.getId()));
            questionWithOptionsVo.setCorrectAnswerVo(correctAnswerVoMap.get(question.getId()));
            return questionWithOptionsVo;
        }).collect(Collectors.toList());
        return questionWithOptionsVoList;
    }









    public QuestionWithOptionsVo getQuestion(Long quId) {
        String key = "question:" + quId;

        // 1. 尝试从缓存获取
        QuestionWithOptionsVo questionWithOptions = (QuestionWithOptionsVo) redisTemplate.opsForValue().get(key);

        if (questionWithOptions != null) {
            return questionWithOptions; // 缓存命中，直接返回
        }

        // 2. 缓存未命中，从数据库加载
        QuestionWithOptionsVo questionWithOptionsVo = this.getQuestionWithOptionById(quId, true);

        // 3. 设置正确答案（如果有必要）
        CorrectAnswerVo correctAnswerVo = new CorrectAnswerVo();
        questionWithOptionsVo.setCorrectAnswerVo(correctAnswerVo);

        // 4. 存入缓存，并设置随机过期时间（例如：基础时间 + 随机偏移量）
        int baseExpireTime = 36000; // 基础过期时间（1小时）
        int randomOffset = new Random().nextInt(600); // 随机偏移量（0~10分钟）
        int finalExpireTime = baseExpireTime + randomOffset; // 最终过期时间（1小时 ~ 1小时10分钟）

        redisTemplate.opsForValue().set(key, questionWithOptionsVo, finalExpireTime, TimeUnit.SECONDS);

        return questionWithOptionsVo;
    }













}
